———— Data Loading ————-

getwd()
[1] "/Users/cory/Projects/DDSAnalytics_customer_attrition"
data <- read.csv("CaseStudy1-data.csv")

———— Data Quality, Structure & Sanity Checks ————-

# Data Dimensionality
dim(data) 
[1] 870  36
# Missing Values
sum(is.na(data)) 
[1] 0
str(data)
'data.frame':   870 obs. of  36 variables:
 $ ID                      : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Age                     : int  32 40 35 32 24 27 41 37 34 34 ...
 $ Attrition               : chr  "No" "No" "No" "No" ...
 $ BusinessTravel          : chr  "Travel_Rarely" "Travel_Rarely" "Travel_Frequently" "Travel_Rarely" ...
 $ DailyRate               : int  117 1308 200 801 567 294 1283 309 1333 653 ...
 $ Department              : chr  "Sales" "Research & Development" "Research & Development" "Sales" ...
 $ DistanceFromHome        : int  13 14 18 1 2 10 5 10 10 10 ...
 $ Education               : int  4 3 2 4 1 2 5 4 4 4 ...
 $ EducationField          : chr  "Life Sciences" "Medical" "Life Sciences" "Marketing" ...
 $ EmployeeCount           : int  1 1 1 1 1 1 1 1 1 1 ...
 $ EmployeeNumber          : int  859 1128 1412 2016 1646 733 1448 1105 1055 1597 ...
 $ EnvironmentSatisfaction : int  2 3 3 3 1 4 2 4 3 4 ...
 $ Gender                  : chr  "Male" "Male" "Male" "Female" ...
 $ HourlyRate              : int  73 44 60 48 32 32 90 88 87 92 ...
 $ JobInvolvement          : int  3 2 3 3 3 3 4 2 3 2 ...
 $ JobLevel                : int  2 5 3 3 1 3 1 2 1 2 ...
 $ JobRole                 : chr  "Sales Executive" "Research Director" "Manufacturing Director" "Sales Executive" ...
 $ JobSatisfaction         : int  4 3 4 4 4 1 3 4 3 3 ...
 $ MaritalStatus           : chr  "Divorced" "Single" "Single" "Married" ...
 $ MonthlyIncome           : int  4403 19626 9362 10422 3760 8793 2127 6694 2220 5063 ...
 $ MonthlyRate             : int  9250 17544 19944 24032 17218 4809 5561 24223 18410 15332 ...
 $ NumCompaniesWorked      : int  2 1 2 1 1 1 2 2 1 1 ...
 $ Over18                  : chr  "Y" "Y" "Y" "Y" ...
 $ OverTime                : chr  "No" "No" "No" "No" ...
 $ PercentSalaryHike       : int  11 14 11 19 13 21 12 14 19 14 ...
 $ PerformanceRating       : int  3 3 3 3 3 4 3 3 3 3 ...
 $ RelationshipSatisfaction: int  3 1 3 3 3 3 1 3 4 2 ...
 $ StandardHours           : int  80 80 80 80 80 80 80 80 80 80 ...
 $ StockOptionLevel        : int  1 0 0 2 0 2 0 3 1 1 ...
 $ TotalWorkingYears       : int  8 21 10 14 6 9 7 8 1 8 ...
 $ TrainingTimesLastYear   : int  3 2 2 3 2 4 5 5 2 3 ...
 $ WorkLifeBalance         : int  2 4 3 3 3 2 2 3 3 2 ...
 $ YearsAtCompany          : int  5 20 2 14 6 9 4 1 1 8 ...
 $ YearsInCurrentRole      : int  2 7 2 10 3 7 2 0 1 2 ...
 $ YearsSinceLastPromotion : int  0 4 2 5 1 1 0 0 0 7 ...
 $ YearsWithCurrManager    : int  3 9 2 7 3 7 3 0 0 7 ...
# Summary statistics
summary(data)
       ID             Age         Attrition         BusinessTravel       DailyRate       Department        DistanceFromHome   Education     EducationField    
 Min.   :  1.0   Min.   :18.00   Length:870         Length:870         Min.   : 103.0   Length:870         Min.   : 1.000   Min.   :1.000   Length:870        
 1st Qu.:218.2   1st Qu.:30.00   Class :character   Class :character   1st Qu.: 472.5   Class :character   1st Qu.: 2.000   1st Qu.:2.000   Class :character  
 Median :435.5   Median :35.00   Mode  :character   Mode  :character   Median : 817.5   Mode  :character   Median : 7.000   Median :3.000   Mode  :character  
 Mean   :435.5   Mean   :36.83                                         Mean   : 815.2                      Mean   : 9.339   Mean   :2.901                     
 3rd Qu.:652.8   3rd Qu.:43.00                                         3rd Qu.:1165.8                      3rd Qu.:14.000   3rd Qu.:4.000                     
 Max.   :870.0   Max.   :60.00                                         Max.   :1499.0                      Max.   :29.000   Max.   :5.000                     
 EmployeeCount EmployeeNumber   EnvironmentSatisfaction    Gender            HourlyRate     JobInvolvement     JobLevel       JobRole          JobSatisfaction
 Min.   :1     Min.   :   1.0   Min.   :1.000           Length:870         Min.   : 30.00   Min.   :1.000   Min.   :1.000   Length:870         Min.   :1.000  
 1st Qu.:1     1st Qu.: 477.2   1st Qu.:2.000           Class :character   1st Qu.: 48.00   1st Qu.:2.000   1st Qu.:1.000   Class :character   1st Qu.:2.000  
 Median :1     Median :1039.0   Median :3.000           Mode  :character   Median : 66.00   Median :3.000   Median :2.000   Mode  :character   Median :3.000  
 Mean   :1     Mean   :1029.8   Mean   :2.701                              Mean   : 65.61   Mean   :2.723   Mean   :2.039                      Mean   :2.709  
 3rd Qu.:1     3rd Qu.:1561.5   3rd Qu.:4.000                              3rd Qu.: 83.00   3rd Qu.:3.000   3rd Qu.:3.000                      3rd Qu.:4.000  
 Max.   :1     Max.   :2064.0   Max.   :4.000                              Max.   :100.00   Max.   :4.000   Max.   :5.000                      Max.   :4.000  
 MaritalStatus      MonthlyIncome    MonthlyRate    NumCompaniesWorked    Over18            OverTime         PercentSalaryHike PerformanceRating
 Length:870         Min.   : 1081   Min.   : 2094   Min.   :0.000      Length:870         Length:870         Min.   :11.0      Min.   :3.000    
 Class :character   1st Qu.: 2840   1st Qu.: 8092   1st Qu.:1.000      Class :character   Class :character   1st Qu.:12.0      1st Qu.:3.000    
 Mode  :character   Median : 4946   Median :14074   Median :2.000      Mode  :character   Mode  :character   Median :14.0      Median :3.000    
                    Mean   : 6390   Mean   :14326   Mean   :2.728                                            Mean   :15.2      Mean   :3.152    
                    3rd Qu.: 8182   3rd Qu.:20456   3rd Qu.:4.000                                            3rd Qu.:18.0      3rd Qu.:3.000    
                    Max.   :19999   Max.   :26997   Max.   :9.000                                            Max.   :25.0      Max.   :4.000    
 RelationshipSatisfaction StandardHours StockOptionLevel TotalWorkingYears TrainingTimesLastYear WorkLifeBalance YearsAtCompany   YearsInCurrentRole
 Min.   :1.000            Min.   :80    Min.   :0.0000   Min.   : 0.00     Min.   :0.000         Min.   :1.000   Min.   : 0.000   Min.   : 0.000    
 1st Qu.:2.000            1st Qu.:80    1st Qu.:0.0000   1st Qu.: 6.00     1st Qu.:2.000         1st Qu.:2.000   1st Qu.: 3.000   1st Qu.: 2.000    
 Median :3.000            Median :80    Median :1.0000   Median :10.00     Median :3.000         Median :3.000   Median : 5.000   Median : 3.000    
 Mean   :2.707            Mean   :80    Mean   :0.7839   Mean   :11.05     Mean   :2.832         Mean   :2.782   Mean   : 6.962   Mean   : 4.205    
 3rd Qu.:4.000            3rd Qu.:80    3rd Qu.:1.0000   3rd Qu.:15.00     3rd Qu.:3.000         3rd Qu.:3.000   3rd Qu.:10.000   3rd Qu.: 7.000    
 Max.   :4.000            Max.   :80    Max.   :3.0000   Max.   :40.00     Max.   :6.000         Max.   :4.000   Max.   :40.000   Max.   :18.000    
 YearsSinceLastPromotion YearsWithCurrManager
 Min.   : 0.000          Min.   : 0.00       
 1st Qu.: 0.000          1st Qu.: 2.00       
 Median : 1.000          Median : 3.00       
 Mean   : 2.169          Mean   : 4.14       
 3rd Qu.: 3.000          3rd Qu.: 7.00       
 Max.   :15.000          Max.   :17.00       
# Duplicate Analysis
sum(duplicated(data))
[1] 0
# Columns in data
colnames(data)
 [1] "ID"                       "Age"                      "Attrition"                "BusinessTravel"           "DailyRate"               
 [6] "Department"               "DistanceFromHome"         "Education"                "EducationField"           "EmployeeCount"           
[11] "EmployeeNumber"           "EnvironmentSatisfaction"  "Gender"                   "HourlyRate"               "JobInvolvement"          
[16] "JobLevel"                 "JobRole"                  "JobSatisfaction"          "MaritalStatus"            "MonthlyIncome"           
[21] "MonthlyRate"              "NumCompaniesWorked"       "Over18"                   "OverTime"                 "PercentSalaryHike"       
[26] "PerformanceRating"        "RelationshipSatisfaction" "StandardHours"            "StockOptionLevel"         "TotalWorkingYears"       
[31] "TrainingTimesLastYear"    "WorkLifeBalance"          "YearsAtCompany"           "YearsInCurrentRole"       "YearsSinceLastPromotion" 
[36] "YearsWithCurrManager"    

————- Target Analysis —————

Summarize the Attrition Rate

# Gives me the proportion of each level in the target variable
prop.table(table(data$Attrition)) * 100

      No      Yes 
83.90805 16.09195 

Frito Lays’ Attrition rate is 16.09%. This means that 16.09% of customers have churned.

str(data)
'data.frame':   870 obs. of  36 variables:
 $ ID                      : int  1 2 3 4 5 6 7 8 9 10 ...
 $ Age                     : int  32 40 35 32 24 27 41 37 34 34 ...
 $ Attrition               : chr  "No" "No" "No" "No" ...
 $ BusinessTravel          : chr  "Travel_Rarely" "Travel_Rarely" "Travel_Frequently" "Travel_Rarely" ...
 $ DailyRate               : int  117 1308 200 801 567 294 1283 309 1333 653 ...
 $ Department              : chr  "Sales" "Research & Development" "Research & Development" "Sales" ...
 $ DistanceFromHome        : int  13 14 18 1 2 10 5 10 10 10 ...
 $ Education               : int  4 3 2 4 1 2 5 4 4 4 ...
 $ EducationField          : chr  "Life Sciences" "Medical" "Life Sciences" "Marketing" ...
 $ EmployeeCount           : int  1 1 1 1 1 1 1 1 1 1 ...
 $ EmployeeNumber          : int  859 1128 1412 2016 1646 733 1448 1105 1055 1597 ...
 $ EnvironmentSatisfaction : int  2 3 3 3 1 4 2 4 3 4 ...
 $ Gender                  : chr  "Male" "Male" "Male" "Female" ...
 $ HourlyRate              : int  73 44 60 48 32 32 90 88 87 92 ...
 $ JobInvolvement          : int  3 2 3 3 3 3 4 2 3 2 ...
 $ JobLevel                : int  2 5 3 3 1 3 1 2 1 2 ...
 $ JobRole                 : chr  "Sales Executive" "Research Director" "Manufacturing Director" "Sales Executive" ...
 $ JobSatisfaction         : int  4 3 4 4 4 1 3 4 3 3 ...
 $ MaritalStatus           : chr  "Divorced" "Single" "Single" "Married" ...
 $ MonthlyIncome           : int  4403 19626 9362 10422 3760 8793 2127 6694 2220 5063 ...
 $ MonthlyRate             : int  9250 17544 19944 24032 17218 4809 5561 24223 18410 15332 ...
 $ NumCompaniesWorked      : int  2 1 2 1 1 1 2 2 1 1 ...
 $ Over18                  : chr  "Y" "Y" "Y" "Y" ...
 $ OverTime                : chr  "No" "No" "No" "No" ...
 $ PercentSalaryHike       : int  11 14 11 19 13 21 12 14 19 14 ...
 $ PerformanceRating       : int  3 3 3 3 3 4 3 3 3 3 ...
 $ RelationshipSatisfaction: int  3 1 3 3 3 3 1 3 4 2 ...
 $ StandardHours           : int  80 80 80 80 80 80 80 80 80 80 ...
 $ StockOptionLevel        : int  1 0 0 2 0 2 0 3 1 1 ...
 $ TotalWorkingYears       : int  8 21 10 14 6 9 7 8 1 8 ...
 $ TrainingTimesLastYear   : int  3 2 2 3 2 4 5 5 2 3 ...
 $ WorkLifeBalance         : int  2 4 3 3 3 2 2 3 3 2 ...
 $ YearsAtCompany          : int  5 20 2 14 6 9 4 1 1 8 ...
 $ YearsInCurrentRole      : int  2 7 2 10 3 7 2 0 1 2 ...
 $ YearsSinceLastPromotion : int  0 4 2 5 1 1 0 0 0 7 ...
 $ YearsWithCurrManager    : int  3 9 2 7 3 7 3 0 0 7 ...
# Unique values in job_level
unique(data$JobLevel)
[1] 2 5 3 1 4
null_summary
                      ID                      Age                Attrition           BusinessTravel                DailyRate               Department 
                       0                        0                        0                        0                        0                        0 
        DistanceFromHome                Education           EducationField            EmployeeCount           EmployeeNumber  EnvironmentSatisfaction 
                       0                        0                        0                        0                        0                        0 
                  Gender               HourlyRate           JobInvolvement                 JobLevel                  JobRole          JobSatisfaction 
                       0                        0                        0                        0                        0                        0 
           MaritalStatus            MonthlyIncome              MonthlyRate       NumCompaniesWorked                   Over18                 OverTime 
                       0                        0                        0                        0                        0                        0 
       PercentSalaryHike        PerformanceRating RelationshipSatisfaction            StandardHours         StockOptionLevel        TotalWorkingYears 
                       0                        0                        0                        0                        0                        0 
   TrainingTimesLastYear          WorkLifeBalance           YearsAtCompany       YearsInCurrentRole  YearsSinceLastPromotion     YearsWithCurrManager 
                       0                        0                        0                        0                        0                        0 

Univariate Analysis

Explore each feature individually to understand its distribution and behavior

glimpse(data)
Rows: 870
Columns: 36
$ ID                       <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,…
$ Age                      <int> 32, 40, 35, 32, 24, 27, 41, 37, 34, 34, 43, 28, 35, 30, 46, 31, 32, 46, 34, 44, 36, 48, 43, 31, 33, 44, 38, 33…
$ Attrition                <chr> "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "N…
$ BusinessTravel           <chr> "Travel_Rarely", "Travel_Rarely", "Travel_Frequently", "Travel_Rarely", "Travel_Frequently", "Travel_Frequentl…
$ DailyRate                <int> 117, 1308, 200, 801, 567, 294, 1283, 309, 1333, 653, 823, 280, 950, 202, 991, 1188, 498, 1144, 181, 170, 913, …
$ Department               <chr> "Sales", "Research & Development", "Research & Development", "Sales", "Research & Development", "Research & De…
$ DistanceFromHome         <int> 13, 14, 18, 1, 2, 10, 5, 10, 10, 10, 6, 1, 7, 2, 1, 20, 3, 7, 2, 1, 9, 2, 9, 2, 1, 5, 14, 9, 24, 19, 9, 21, 2,…
$ Education                <int> 4, 3, 2, 4, 1, 2, 5, 4, 4, 4, 3, 2, 3, 1, 2, 2, 4, 4, 4, 4, 2, 1, 5, 4, 3, 3, 3, 4, 4, 4, 2, 3, 3, 4, 4, 3, 3,…
$ EducationField           <chr> "Life Sciences", "Medical", "Life Sciences", "Marketing", "Technical Degree", "Life Sciences", "Medical", "Lif…
$ EmployeeCount            <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,…
$ EmployeeNumber           <int> 859, 1128, 1412, 2016, 1646, 733, 1448, 1105, 1055, 1597, 1866, 1858, 845, 508, 1314, 947, 966, 487, 1755, 190…
$ EnvironmentSatisfaction  <int> 2, 3, 3, 3, 1, 4, 2, 4, 3, 4, 1, 3, 3, 3, 4, 4, 3, 3, 4, 2, 2, 2, 4, 4, 2, 2, 3, 1, 1, 4, 4, 2, 3, 4, 4, 2, 4,…
$ Gender                   <chr> "Male", "Male", "Male", "Female", "Female", "Male", "Male", "Female", "Female", "Male", "Female", "Male", "Mal…
$ HourlyRate               <int> 73, 44, 60, 48, 32, 32, 90, 88, 87, 92, 81, 43, 59, 72, 44, 45, 93, 30, 97, 78, 48, 56, 72, 54, 42, 88, 80, 77…
$ JobInvolvement           <int> 3, 2, 3, 3, 3, 3, 4, 2, 3, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 2, 4, 3, 3, 2, 3, 3, 3, 3, 3, 1, 4, 1, 2, 2, 4, 2,…
$ JobLevel                 <int> 2, 5, 3, 3, 1, 3, 1, 2, 1, 2, 5, 1, 3, 1, 1, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 5, 2, 2, 3, 1, 2, 1, 4, 1, 2, 1, 3,…
$ JobRole                  <chr> "Sales Executive", "Research Director", "Manufacturing Director", "Sales Executive", "Research Scientist", "Ma…
$ JobSatisfaction          <int> 4, 3, 4, 4, 4, 1, 3, 4, 3, 3, 3, 4, 3, 2, 1, 3, 1, 3, 4, 1, 2, 2, 3, 1, 4, 2, 2, 1, 1, 4, 4, 2, 2, 3, 4, 2, 1,…
$ MaritalStatus            <chr> "Divorced", "Single", "Single", "Married", "Single", "Divorced", "Married", "Divorced", "Married", "Married", …
$ MonthlyIncome            <int> 4403, 19626, 9362, 10422, 3760, 8793, 2127, 6694, 2220, 5063, 19392, 2706, 10221, 2476, 3423, 6932, 6725, 5258…
$ MonthlyRate              <int> 9250, 17544, 19944, 24032, 17218, 4809, 5561, 24223, 18410, 15332, 22539, 10494, 18869, 17434, 22957, 24406, 1…
$ NumCompaniesWorked       <int> 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 7, 1, 3, 1, 6, 1, 1, 2, 0, 2, 2, 3, 3, 7, 0, 7, 0, 0, 6, 0, 0, 1, 3, 6, 8, 1, 9,…
$ Over18                   <chr> "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", "Y", …
$ OverTime                 <chr> "No", "No", "No", "No", "Yes", "No", "Yes", "Yes", "Yes", "No", "No", "No", "No", "No", "No", "No", "No", "No"…
$ PercentSalaryHike        <int> 11, 14, 11, 19, 13, 21, 12, 14, 19, 14, 13, 15, 21, 18, 12, 13, 12, 14, 14, 15, 11, 12, 13, 13, 14, 11, 11, 17…
$ PerformanceRating        <int> 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3,…
$ RelationshipSatisfaction <int> 3, 1, 3, 3, 3, 3, 1, 3, 4, 2, 4, 2, 2, 1, 3, 4, 3, 3, 1, 4, 3, 4, 2, 4, 1, 3, 4, 1, 2, 1, 4, 4, 2, 2, 2, 3, 3,…
$ StandardHours            <int> 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, 80…
$ StockOptionLevel         <int> 1, 0, 0, 2, 0, 2, 0, 3, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 3, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 3, 3, 1, 1, 0, 0, 0,…
$ TotalWorkingYears        <int> 8, 21, 10, 14, 6, 9, 7, 8, 1, 8, 21, 3, 17, 1, 10, 9, 8, 7, 6, 10, 13, 12, 10, 10, 6, 26, 10, 6, 15, 5, 9, 14,…
$ TrainingTimesLastYear    <int> 3, 2, 2, 3, 2, 4, 5, 5, 2, 3, 2, 2, 3, 3, 3, 2, 2, 2, 3, 5, 2, 3, 3, 3, 3, 5, 3, 3, 2, 3, 2, 6, 2, 2, 1, 3, 3,…
$ WorkLifeBalance          <int> 2, 4, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, 4, 3, 4, 2, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 4, 3, 2, 3, 3, 1, 3,…
$ YearsAtCompany           <int> 5, 20, 2, 14, 6, 9, 4, 1, 1, 8, 16, 3, 8, 1, 7, 9, 8, 1, 5, 2, 3, 2, 8, 5, 5, 22, 9, 5, 2, 4, 8, 14, 7, 8, 1, …
$ YearsInCurrentRole       <int> 2, 7, 2, 10, 3, 7, 2, 0, 1, 2, 12, 2, 5, 0, 6, 8, 7, 0, 0, 0, 2, 2, 7, 2, 0, 9, 8, 2, 2, 3, 7, 11, 7, 0, 0, 1,…
$ YearsSinceLastPromotion  <int> 0, 4, 2, 5, 1, 1, 0, 0, 0, 7, 6, 2, 1, 0, 5, 0, 6, 0, 1, 2, 0, 2, 4, 0, 1, 3, 7, 0, 2, 1, 0, 2, 7, 1, 0, 0, 6,…
$ YearsWithCurrManager     <int> 3, 9, 2, 7, 3, 7, 3, 0, 0, 7, 14, 2, 6, 0, 7, 0, 3, 0, 2, 2, 2, 2, 7, 3, 4, 10, 7, 3, 2, 2, 7, 13, 7, 7, 0, 3,…

Age Distribution

There is a slight right skew to the Age feature with most of the employees being around the age of 30-40.

Business Travel Distribution

The majority of employees do not travel for business purposes.

DailyRate Distribution

The Daily Rate feature appears to be uniformly distributed between 100 and 1500. No particulary useful distribution insights can be derived.

Department Distribution

The majority of employees work in the Research & Development department, followed by Sales and then Human Resources.

DistanceFromHome Distribution

There is a heavy concentration of employees living within 10 miles of work, with a gradual decrease in number of employees as distance increases.

Education Distribution

Education has a normal distribution with the highest concentration of employees centering around level 3.

EducationField Distribution

The majority of employees have a background in Life Sciences, followed by Medical and then Marketing.

EnvironmentalSatisfaction Distribution

The environmental satisfaction seems to show that more employees are satisfied than not.

Gender Distribution

The gender distribution is showing that there are more Males than females at the company.

HourlyRate Distribution

No useful distribution insights can be derived from the Hourly Rate feature.

JobInvolvement Distribution

ggplot(data, aes(x = JobInvolvement)) +
  geom_bar() +
  geom_text(
    stat = "count",
    aes(label = ..count..),
    vjust = -0.6, size = 4, color = "black"
  ) +
  scale_y_continuous(expand = expansion(mult = c(0.02, 0.15))) +  
  theme_economist() +
  labs(title = "Job Involvement Distribution", x = "Job Involvement Level", y = "Count") +
  theme(
    plot.title = element_text(hjust = 0.5, margin = margin(b = 12)),
    axis.title.x = element_text(margin = margin(t = 12)),
    axis.title.y = element_text(margin = margin(r = 12))
    )

The job involvement appears to have a the majority of level 3 involvement, with level 4 being the least common.

JobLevel Distribution

The job level distribution shows that the majority of employees are at level 1, with a decreasing number of employees as job level increases.

MaritalStatus Distribution

Most employees are single.

MonthlyIncome Distribution

The Monthly Income feature appears to be right skewed with most employees earning between $2000 and $8000 per month.

NumCompaniesWorked Distribution

The number of companies worked feature appears to be right skewed with most employees having worked at 1-3 companies prior to their current employment.

OverTime Distribution

Majority of employees do not work overtime.

PercentSalaryHike Distribution

Percent Salary hike is demonstrating a heavy right skew with most employees receiving between 10-15% salary hikes.

PerformanceRating Distribution

Majority of employees have a performance rating of 3, with very few employees receiving a rating of 4.

RelationshipSatisfaction Distribution

Majority of employees have a relationship satisfaction level of 3 or 4, with level 2 being the least common by a slim margin.

StandardHours Distribution

All employees have standard hours of 80.

StockOptionLevel Distribution

Majority of employees have a stock option level of 0, with very few employees having a stock option level of 3.

TotalWorkingYears Distribution

The Total Working Years feature appears to be right skewed with most employees having between 0-10 years of total working experience.

TrainingTimesLastYear Distribution

Majority of employees have undergone training 2-3 times in the last year.

WorkLifeBalance Distribution

Majority of employees have a work life balance level of 3, with level 1 being the least common.

YearsAtCompany Distribution

The Years At Company feature appears to be right skewed with most employees having between 0-10 years at the company.

YearsInCurrentRole Distribution

The Years In Current Role feature appears to be right skewed with most employees having between 0-7 years in their current role.

YearsSinceLastPromotion Distribution

The Years Since Last Promotion feature appears to be right skewed with most employees having between 0-3 years since their last promotion.

YearsWithCurrManager Distribution

The Years With Current Manager feature appears to be right skewed with most employees having between 0-7 years with their current manager.

———— Bivariate Analysis ————-

LS0tCnRpdGxlOiAiRnJpdG8gTGF5OiBDdXN0b21lciBBdHRyaXRpb24iCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShjYXJldCkKbGlicmFyeShlMTA3MSkKbGlicmFyeShjbGFzcykKbGlicmFyeShnZ3RoZW1lcykKYGBgCgoKIyAtLS0tLS0tLS0tLS0gRGF0YSBMb2FkaW5nIC0tLS0tLS0tLS0tLS0KYGBge3J9CmdldHdkKCkKZGF0YSA8LSByZWFkLmNzdigiQ2FzZVN0dWR5MS1kYXRhLmNzdiIpCmBgYAoKIyAtLS0tLS0tLS0tLS0gRGF0YSBRdWFsaXR5LCBTdHJ1Y3R1cmUgJiBTYW5pdHkgQ2hlY2tzIC0tLS0tLS0tLS0tLS0KYGBge3J9CiMgRGF0YSBEaW1lbnNpb25hbGl0eQpkaW0oZGF0YSkgCmBgYAoKYGBge3J9CiMgTWlzc2luZyBWYWx1ZXMKc3VtKGlzLm5hKGRhdGEpKSAKYGBgCgpgYGB7cn0Kc3RyKGRhdGEpCmBgYAoKCmBgYHtyfQojIFN1bW1hcnkgc3RhdGlzdGljcwpzdW1tYXJ5KGRhdGEpCmBgYAoKYGBge3J9CiMgRHVwbGljYXRlIEFuYWx5c2lzCnN1bShkdXBsaWNhdGVkKGRhdGEpKQpgYGAKCmBgYHtyfQojIENvbHVtbnMgaW4gZGF0YQpjb2xuYW1lcyhkYXRhKQpgYGAKCmBgYHtyfQojQ2hlY2tpbmcgb3V0IHRoZSBBdHRyaXRpb24gRGlzdHJpYnV0aW9uCmdncGxvdChkYXRhID0gZGF0YSwgbWFwcGluZyA9IGFlcyh4ID0gQXR0cml0aW9uKSkgICsgCiAgZ2VvbV9iYXIoKSArIAogIGdlb21fdGV4dCgKICAgIHN0YXQgPSAiY291bnQiLAogICAgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwKICAgIHZqdXN0ID0gLTAuNSwKICAgIHNpemUgPSA0LAogICAgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJUb3RhbCBBdHRyaXRpb24gRGlzdHJpYnV0aW9uIgogICAgICApCmBgYAoKCiMgLS0tLS0tLS0tLS0tLSBUYXJnZXQgQW5hbHlzaXMgLS0tLS0tLS0tLS0tLS0tCgojIFN1bW1hcml6ZSB0aGUgQXR0cml0aW9uIFJhdGUgIApgYGB7cn0KIyBHaXZlcyBtZSBhIGlucHV0IGxldmVsIGJyZWFrZG93biBvZiB0aGUgdGFyZ2V0IHZhcmlhYmxlCmRhdGEkQXR0cml0aW9uCgojIENyZWF0ZXMgYSBjb3VudCB0YWJsZSAoc3VwZXIgdXNlZnVsISkKdGFibGUoZGF0YSRBdHRyaXRpb24pCgojIEdpdmVzIG1lIHRoZSBwcm9wb3J0aW9uIG9mIGVhY2ggbGV2ZWwgaW4gdGhlIHRhcmdldCB2YXJpYWJsZQpwcm9wLnRhYmxlKHRhYmxlKGRhdGEkQXR0cml0aW9uKSkgKiAxMDAKYGBgCgpGcml0byBMYXlzJyBBdHRyaXRpb24gcmF0ZSBpcyAxNi4wOSUuIFRoaXMgbWVhbnMgdGhhdCAxNi4wOSUgb2YgY3VzdG9tZXJzIGhhdmUgY2h1cm5lZC4KCgpgYGB7cn0Kc3RyKGRhdGEpCmBgYAoKYGBge3J9CiMgVW5pcXVlIHZhbHVlcyBpbiBqb2JfbGV2ZWwKdW5pcXVlKGRhdGEkSm9iTGV2ZWwpCmBgYAoKYGBge3J9Cm51bGxfc3VtbWFyeSA8LSBzYXBwbHkoZGF0YSwgZnVuY3Rpb24oeCkgc3VtKGlzLm5hKHgpKSkKbnVsbF9zdW1tYXJ5CmBgYAoKIyBVbml2YXJpYXRlIEFuYWx5c2lzCiMgRXhwbG9yZSBlYWNoIGZlYXR1cmUgaW5kaXZpZHVhbGx5IHRvIHVuZGVyc3RhbmQgaXRzIGRpc3RyaWJ1dGlvbiBhbmQgYmVoYXZpb3IKCmBgYHtyfQpnbGltcHNlKGRhdGEpCmBgYAojIEFnZSBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IEFnZSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oKSArCiAgZ2VvbV9kZW5zaXR5KGNvbG9yID0gImRhcmtyZWQiLCBzaXplID0gMS4yKSArCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiQWdlIERpc3RyaWJ1dGlvbiIsIHggPSAiQWdlIiwgeSA9ICJDb3VudCIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAxMikpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMTIpKQogICAgKQogICkKYGBgClRoZXJlIGlzIGEgc2xpZ2h0IHJpZ2h0IHNrZXcgdG8gdGhlIEFnZSBmZWF0dXJlIHdpdGggbW9zdCBvZiB0aGUgZW1wbG95ZWVzIGJlaW5nIGFyb3VuZCB0aGUgYWdlIG9mIDMwLTQwLgoKIyBCdXNpbmVzcyBUcmF2ZWwgRGlzdHJpYnV0aW9uCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBCdXNpbmVzc1RyYXZlbCkpICsKICBnZW9tX2JhcigpICsKICBnZW9tX3RleHQoCiAgICBzdGF0ID0gImNvdW50IiwKICAgIGFlcyhsYWJlbCA9IC4uY291bnQuLiksCiAgICB2anVzdCA9IC0wLjYsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDIsIDAuMTUpKSkgKyAgCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiQnVzaW5lc3MgVHJhdmVsIERpc3RyaWJ1dGlvbiIsIHggPSAiQnVzaW5lc3MgVHJhdmVsIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCgpgYGAKClRoZSBtYWpvcml0eSBvZiBlbXBsb3llZXMgZG8gbm90IHRyYXZlbCBmb3IgYnVzaW5lc3MgcHVycG9zZXMuCgojIERhaWx5UmF0ZSBEaXN0cmlidXRpb24KCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBEYWlseVJhdGUpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMTApICsKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJEYWlseSBSYXRlIERpc3RyaWJ1dGlvbiIsIHggPSAiRGFpbHkgUmF0ZSIsIHkgPSAiQ291bnQiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKICApKSkKCnN1bW1hcnkoZGF0YSREYWlseVJhdGUpCmBgYAoKVGhlIERhaWx5IFJhdGUgZmVhdHVyZSBhcHBlYXJzIHRvIGJlIHVuaWZvcm1seSBkaXN0cmlidXRlZCBiZXR3ZWVuIDEwMCBhbmQgMTUwMC4gTm8gcGFydGljdWxhcnkgdXNlZnVsIGRpc3RyaWJ1dGlvbiBpbnNpZ2h0cyBjYW4gYmUgZGVyaXZlZC4KCiMgRGVwYXJ0bWVudCBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IERlcGFydG1lbnQpKSArCiAgZ2VvbV9iYXIoKSArCiAgZ2VvbV90ZXh0KAogICAgc3RhdCA9ICJjb3VudCIsCiAgICBhZXMobGFiZWwgPSAuLmNvdW50Li4pLAogICAgdmp1c3QgPSAtMC42LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjAyLCAwLjE1KSkpICsgIAogIHRoZW1lX2Vjb25vbWlzdCgpICsKICBsYWJzKHRpdGxlID0gIkRlcGFydG1lbnQgRGlzdHJpYnV0aW9uIiwgeCA9ICJEZXBhcnRtZW50IiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCmBgYAoKVGhlIG1ham9yaXR5IG9mIGVtcGxveWVlcyB3b3JrIGluIHRoZSBSZXNlYXJjaCAmIERldmVsb3BtZW50IGRlcGFydG1lbnQsIGZvbGxvd2VkIGJ5IFNhbGVzIGFuZCB0aGVuIEh1bWFuIFJlc291cmNlcy4KCiMgRGlzdGFuY2VGcm9tSG9tZSBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IERpc3RhbmNlRnJvbUhvbWUpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkgKwogIHRoZW1lX2Vjb25vbWlzdCgpICsKICBsYWJzKHRpdGxlID0gIkRpc3RhbmNlIEZyb20gSG9tZSBEaXN0cmlidXRpb24iLCB4ID0gIkRpc3RhbmNlIEZyb20gSG9tZSAobWlsZXMpIiwgeSA9ICJDb3VudCIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAxMikpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMTIpKQogICAgKQogICkKYGBgCgpUaGVyZSBpcyBhIGhlYXZ5IGNvbmNlbnRyYXRpb24gb2YgZW1wbG95ZWVzIGxpdmluZyB3aXRoaW4gMTAgbWlsZXMgb2Ygd29yaywgd2l0aCBhIGdyYWR1YWwgZGVjcmVhc2UgaW4gbnVtYmVyIG9mIGVtcGxveWVlcyBhcyBkaXN0YW5jZSBpbmNyZWFzZXMuCgojIEVkdWNhdGlvbiBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IEVkdWNhdGlvbikpICsKICBnZW9tX2JhcigpICsKICBnZW9tX3RleHQoCiAgICBzdGF0ID0gImNvdW50IiwKICAgIGFlcyhsYWJlbCA9IC4uY291bnQuLiksCiAgICB2anVzdCA9IC0wLjYsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDIsIDAuMTUpKSkgKyAgCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiRWR1Y2F0aW9uIERpc3RyaWJ1dGlvbiIsIHggPSAiRWR1Y2F0aW9uIExldmVsIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCmBgYAogCkVkdWNhdGlvbiBoYXMgYSBub3JtYWwgZGlzdHJpYnV0aW9uIHdpdGggdGhlIGhpZ2hlc3QgY29uY2VudHJhdGlvbiBvZiBlbXBsb3llZXMgY2VudGVyaW5nIGFyb3VuZCBsZXZlbCAzLgoKIyBFZHVjYXRpb25GaWVsZCBEaXN0cmlidXRpb24KCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBFZHVjYXRpb25GaWVsZCkpICsKICBnZW9tX2JhcigpICsKICBnZW9tX3RleHQoCiAgICBzdGF0ID0gImNvdW50IiwKICAgIGFlcyhsYWJlbCA9IC4uY291bnQuLiksCiAgICB2anVzdCA9IC0wLjYsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDIsIDAuMTUpKSkgKwogIHRoZW1lX2Vjb25vbWlzdCgpICsKICBsYWJzKHRpdGxlID0gIkVkdWNhdGlvbiBGaWVsZCBEaXN0cmlidXRpb24iLCB4ID0gIkVkdWNhdGlvbiBGaWVsZCIsIHkgPSAiQ291bnQiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSAgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpLAogICAgYXhpcy50ZXh0LnggICA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEsIHZqdXN0ID0gMSkgICAjIPCfkYggcm90YXRlcyBsYWJlbHMKICApCgpgYGAKClRoZSBtYWpvcml0eSBvZiBlbXBsb3llZXMgaGF2ZSBhIGJhY2tncm91bmQgaW4gTGlmZSBTY2llbmNlcywgZm9sbG93ZWQgYnkgTWVkaWNhbCBhbmQgdGhlbiBNYXJrZXRpbmcuCgojIEVudmlyb25tZW50YWxTYXRpc2ZhY3Rpb24gRGlzdHJpYnV0aW9uCgpgYGB7cn0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gRW52aXJvbm1lbnRTYXRpc2ZhY3Rpb24pKSArCiAgZ2VvbV9iYXIoKSArCiAgZ2VvbV90ZXh0KAogICAgc3RhdCA9ICJjb3VudCIsCiAgICBhZXMobGFiZWwgPSAuLmNvdW50Li4pLAogICAgdmp1c3QgPSAtMC42LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjAyLCAwLjE1KSkpICsgIAogIHRoZW1lX2Vjb25vbWlzdCgpICsKICBsYWJzKHRpdGxlID0gIkVudmlyb25tZW50YWwgU2F0aXNmYWN0aW9uIERpc3RyaWJ1dGlvbiIsIHggPSAiRW52aXJvbm1lbnRhbCBTYXRpc2ZhY3Rpb24gTGV2ZWwiLCB5ID0gIkNvdW50IikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKYGBgCgpUaGUgZW52aXJvbm1lbnRhbCBzYXRpc2ZhY3Rpb24gc2VlbXMgdG8gc2hvdyB0aGF0IG1vcmUgZW1wbG95ZWVzIGFyZSBzYXRpc2ZpZWQgdGhhbiBub3QuCgojIEdlbmRlciBEaXN0cmlidXRpb24KCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBHZW5kZXIpKSArCiAgZ2VvbV9iYXIoKSArCiAgZ2VvbV90ZXh0KAogICAgc3RhdCA9ICJjb3VudCIsCiAgICBhZXMobGFiZWwgPSAuLmNvdW50Li4pLAogICAgdmp1c3QgPSAtMC42LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjAyLCAwLjE1KSkpICsgIAogIHRoZW1lX2Vjb25vbWlzdCgpICsKICBsYWJzKHRpdGxlID0gIkdlbmRlciBEaXN0cmlidXRpb24iLCB4ID0gIkdlbmRlciIsIHkgPSAiQ291bnQiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAxMikpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMTIpKQogICAgKQpgYGAKClRoZSBnZW5kZXIgZGlzdHJpYnV0aW9uIGlzIHNob3dpbmcgdGhhdCB0aGVyZSBhcmUgbW9yZSBNYWxlcyB0aGFuIGZlbWFsZXMgYXQgdGhlIGNvbXBhbnkuCgojIEhvdXJseVJhdGUgRGlzdHJpYnV0aW9uCgpgYGB7cn0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gSG91cmx5UmF0ZSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKSArCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiSG91cmx5IFJhdGUgRGlzdHJpYnV0aW9uIiwgeCA9ICJIb3VybHkgUmF0ZSIsIHkgPSAiQ291bnQiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKICApCmBgYAoKTm8gdXNlZnVsIGRpc3RyaWJ1dGlvbiBpbnNpZ2h0cyBjYW4gYmUgZGVyaXZlZCBmcm9tIHRoZSBIb3VybHkgUmF0ZSBmZWF0dXJlLgoKIyBKb2JJbnZvbHZlbWVudCBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IEpvYkludm9sdmVtZW50KSkgKwogIGdlb21fYmFyKCkgKwogIGdlb21fdGV4dCgKICAgIHN0YXQgPSAiY291bnQiLAogICAgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwKICAgIHZqdXN0ID0gLTAuNiwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIgogICkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMiwgMC4xNSkpKSArICAKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJKb2IgSW52b2x2ZW1lbnQgRGlzdHJpYnV0aW9uIiwgeCA9ICJKb2IgSW52b2x2ZW1lbnQgTGV2ZWwiLCB5ID0gIkNvdW50IikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKYGBgCgpUaGUgam9iIGludm9sdmVtZW50IGFwcGVhcnMgdG8gaGF2ZSBhIHRoZSBtYWpvcml0eSBvZiBsZXZlbCAzIGludm9sdmVtZW50LCB3aXRoIGxldmVsIDQgYmVpbmcgdGhlIGxlYXN0IGNvbW1vbi4KCiMgSm9iTGV2ZWwgRGlzdHJpYnV0aW9uCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBKb2JMZXZlbCkpICsKICBnZW9tX2JhcigpICsKICBnZW9tX3RleHQoCiAgICBzdGF0ID0gImNvdW50IiwKICAgIGFlcyhsYWJlbCA9IC4uY291bnQuLiksCiAgICB2anVzdCA9IC0wLjYsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDIsIDAuMTUpKSkgKyAgCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiSm9iIExldmVsIERpc3RyaWJ1dGlvbiIsIHggPSAiSm9iIExldmVsIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCmBgYAoKVGhlIGpvYiBsZXZlbCBkaXN0cmlidXRpb24gc2hvd3MgdGhhdCB0aGUgbWFqb3JpdHkgb2YgZW1wbG95ZWVzIGFyZSBhdCBsZXZlbCAxLCB3aXRoIGEgZGVjcmVhc2luZyBudW1iZXIgb2YgZW1wbG95ZWVzIGFzIGpvYiBsZXZlbCBpbmNyZWFzZXMuCgojIE1hcml0YWxTdGF0dXMgRGlzdHJpYnV0aW9uCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBNYXJpdGFsU3RhdHVzKSkgKwogIGdlb21fYmFyKCkgKwogIGdlb21fdGV4dCgKICAgIHN0YXQgPSAiY291bnQiLAogICAgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwKICAgIHZqdXN0ID0gLTAuNiwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIgogICkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMiwgMC4xNSkpKSArICAKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJNYXJpdGFsIFN0YXR1cyBEaXN0cmlidXRpb24iLCB4ID0gIk1hcml0YWwgU3RhdHVzIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCmBgYAoKTW9zdCBlbXBsb3llZXMgYXJlIHNpbmdsZS4KCiMgTW9udGhseUluY29tZSBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IE1vbnRobHlJbmNvbWUpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gNTAwKSArCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiTW9udGhseSBJbmNvbWUgRGlzdHJpYnV0aW9uIiwgeCA9ICJNb250aGx5IEluY29tZSIsIHkgPSAiQ291bnQiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKICApCmBgYAoKVGhlIE1vbnRobHkgSW5jb21lIGZlYXR1cmUgYXBwZWFycyB0byBiZSByaWdodCBza2V3ZWQgd2l0aCBtb3N0IGVtcGxveWVlcyBlYXJuaW5nIGJldHdlZW4gJDIwMDAgYW5kICQ4MDAwIHBlciBtb250aC4KCiMgTnVtQ29tcGFuaWVzV29ya2VkIERpc3RyaWJ1dGlvbgpgYGB7cn0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gTnVtQ29tcGFuaWVzV29ya2VkKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IC44KSArCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiTnVtYmVyIG9mIENvbXBhbmllcyBXb3JrZWQgRGlzdHJpYnV0aW9uIiwgeCA9ICJOdW1iZXIgb2YgQ29tcGFuaWVzIFdvcmtlZCIsIHkgPSAiQ291bnQiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKICApCmBgYAoKVGhlIG51bWJlciBvZiBjb21wYW5pZXMgd29ya2VkIGZlYXR1cmUgYXBwZWFycyB0byBiZSByaWdodCBza2V3ZWQgd2l0aCBtb3N0IGVtcGxveWVlcyBoYXZpbmcgd29ya2VkIGF0IDEtMyBjb21wYW5pZXMgcHJpb3IgdG8gdGhlaXIgY3VycmVudCBlbXBsb3ltZW50LgoKIyBPdmVyVGltZSBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IE92ZXJUaW1lKSkgKwogIGdlb21fYmFyKCkgKwogIGdlb21fdGV4dCgKICAgIHN0YXQgPSAiY291bnQiLAogICAgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwKICAgIHZqdXN0ID0gLTAuNiwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIgogICkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMiwgMC4xNSkpKSArICAKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJPdmVyVGltZSBEaXN0cmlidXRpb24iLCB4ID0gIk92ZXJUaW1lIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCmBgYAoKTWFqb3JpdHkgb2YgZW1wbG95ZWVzIGRvIG5vdCB3b3JrIG92ZXJ0aW1lLgoKIyBQZXJjZW50U2FsYXJ5SGlrZSBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IFBlcmNlbnRTYWxhcnlIaWtlKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpICsKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJQZXJjZW50IFNhbGFyeSBIaWtlIERpc3RyaWJ1dGlvbiIsIHggPSAiUGVyY2VudCBTYWxhcnkgSGlrZSIsIHkgPSAiQ291bnQiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKICApCmBgYAoKUGVyY2VudCBTYWxhcnkgaGlrZSBpcyBkZW1vbnN0cmF0aW5nIGEgaGVhdnkgcmlnaHQgc2tldyB3aXRoIG1vc3QgZW1wbG95ZWVzIHJlY2VpdmluZyBiZXR3ZWVuIDEwLTE1JSBzYWxhcnkgaGlrZXMuCgojIFBlcmZvcm1hbmNlUmF0aW5nIERpc3RyaWJ1dGlvbgpgYGB7cn0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gUGVyZm9ybWFuY2VSYXRpbmcpKSArCiAgZ2VvbV9iYXIoKSArCiAgZ2VvbV90ZXh0KAogICAgc3RhdCA9ICJjb3VudCIsCiAgICBhZXMobGFiZWwgPSAuLmNvdW50Li4pLAogICAgdmp1c3QgPSAtMC42LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjAyLCAwLjE1KSkpICsgIAogIHRoZW1lX2Vjb25vbWlzdCgpICsKICBsYWJzKHRpdGxlID0gIlBlcmZvcm1hbmNlIFJhdGluZyBEaXN0cmlidXRpb24iLCB4ID0gIlBlcmZvcm1hbmNlIFJhdGluZyIsIHkgPSAiQ291bnQiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAxMikpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMTIpKQogICAgKQoKYGBgCgpNYWpvcml0eSBvZiBlbXBsb3llZXMgaGF2ZSBhIHBlcmZvcm1hbmNlIHJhdGluZyBvZiAzLCB3aXRoIHZlcnkgZmV3IGVtcGxveWVlcyByZWNlaXZpbmcgYSByYXRpbmcgb2YgNC4KCiMgUmVsYXRpb25zaGlwU2F0aXNmYWN0aW9uIERpc3RyaWJ1dGlvbgpgYGB7cn0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gUmVsYXRpb25zaGlwU2F0aXNmYWN0aW9uKSkgKwogIGdlb21fYmFyKCkgKwogIGdlb21fdGV4dCgKICAgIHN0YXQgPSAiY291bnQiLAogICAgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwKICAgIHZqdXN0ID0gLTAuNiwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIgogICkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMiwgMC4xNSkpKSArICAKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJSZWxhdGlvbnNoaXAgU2F0aXNmYWN0aW9uIERpc3RyaWJ1dGlvbiIsIHggPSAiUmVsYXRpb25zaGlwIFNhdGlzZmFjdGlvbiBMZXZlbCIsIHkgPSAiQ291bnQiKSArCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAxMikpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMTIpKQogICAgKQpgYGAKCk1ham9yaXR5IG9mIGVtcGxveWVlcyBoYXZlIGEgcmVsYXRpb25zaGlwIHNhdGlzZmFjdGlvbiBsZXZlbCBvZiAzIG9yIDQsIHdpdGggbGV2ZWwgMiBiZWluZyB0aGUgbGVhc3QgY29tbW9uIGJ5IGEgc2xpbSBtYXJnaW4uCgojIFN0YW5kYXJkSG91cnMgRGlzdHJpYnV0aW9uCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBTdGFuZGFyZEhvdXJzKSkgKwogIGdlb21fYmFyKCkgKwogIGdlb21fdGV4dCgKICAgIHN0YXQgPSAiY291bnQiLAogICAgYWVzKGxhYmVsID0gLi5jb3VudC4uKSwKICAgIHZqdXN0ID0gLTAuNiwgc2l6ZSA9IDQsIGNvbG9yID0gImJsYWNrIgogICkgKwogIHNjYWxlX3lfY29udGludW91cyhleHBhbmQgPSBleHBhbnNpb24obXVsdCA9IGMoMC4wMiwgMC4xNSkpKSArICAKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJTdGFuZGFyZCBIb3VycyBEaXN0cmlidXRpb24iLCB4ID0gIlN0YW5kYXJkIEhvdXJzIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCmBgYAoKQWxsIGVtcGxveWVlcyBoYXZlIHN0YW5kYXJkIGhvdXJzIG9mIDgwLgoKIyBTdG9ja09wdGlvbkxldmVsIERpc3RyaWJ1dGlvbgpgYGB7cn0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gU3RvY2tPcHRpb25MZXZlbCkpICsKICBnZW9tX2JhcigpICsKICBnZW9tX3RleHQoCiAgICBzdGF0ID0gImNvdW50IiwKICAgIGFlcyhsYWJlbCA9IC4uY291bnQuLiksCiAgICB2anVzdCA9IC0wLjYsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDIsIDAuMTUpKSkgKyAgCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiU3RvY2sgT3B0aW9uIExldmVsIERpc3RyaWJ1dGlvbiIsIHggPSAiU3RvY2sgT3B0aW9uIExldmVsIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCmBgYAoKTWFqb3JpdHkgb2YgZW1wbG95ZWVzIGhhdmUgYSBzdG9jayBvcHRpb24gbGV2ZWwgb2YgMCwgd2l0aCB2ZXJ5IGZldyBlbXBsb3llZXMgaGF2aW5nIGEgc3RvY2sgb3B0aW9uIGxldmVsIG9mIDMuCgojIFRvdGFsV29ya2luZ1llYXJzIERpc3RyaWJ1dGlvbgpgYGB7cn0KZ2dwbG90KGRhdGEsIGFlcyh4ID0gVG90YWxXb3JraW5nWWVhcnMpKSArIAogIGdlb21faGlzdG9ncmFtKGJpbndpZHRoID0gMSkgKwogIHRoZW1lX2Vjb25vbWlzdCgpICsKICBsYWJzKHRpdGxlID0gIlRvdGFsIFdvcmtpbmcgWWVhcnMgRGlzdHJpYnV0aW9uIiwgeCA9ICJUb3RhbCBXb3JraW5nIFllYXJzIiwgeSA9ICJDb3VudCIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAxMikpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMTIpKQogICAgKQogICkKYGBgCgpUaGUgVG90YWwgV29ya2luZyBZZWFycyBmZWF0dXJlIGFwcGVhcnMgdG8gYmUgcmlnaHQgc2tld2VkIHdpdGggbW9zdCBlbXBsb3llZXMgaGF2aW5nIGJldHdlZW4gMC0xMCB5ZWFycyBvZiB0b3RhbCB3b3JraW5nIGV4cGVyaWVuY2UuCgojIFRyYWluaW5nVGltZXNMYXN0WWVhciBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IFRyYWluaW5nVGltZXNMYXN0WWVhcikpICsKICBnZW9tX2JhcigpICsKICBnZW9tX3RleHQoCiAgICBzdGF0ID0gImNvdW50IiwKICAgIGFlcyhsYWJlbCA9IC4uY291bnQuLiksCiAgICB2anVzdCA9IC0wLjYsIHNpemUgPSA0LCBjb2xvciA9ICJibGFjayIKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMoZXhwYW5kID0gZXhwYW5zaW9uKG11bHQgPSBjKDAuMDIsIDAuMTUpKSkgKyAgCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiVHJhaW5pbmcgVGltZXMgTGFzdCBZZWFyIERpc3RyaWJ1dGlvbiIsIHggPSAiVHJhaW5pbmcgVGltZXMgTGFzdCBZZWFyIiwgeSA9ICJDb3VudCIpICsKICB0aGVtZSgKICAgIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUsIG1hcmdpbiA9IG1hcmdpbihiID0gMTIpKSwKICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IDEyKSksCiAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHIgPSAxMikpCiAgICApCmBgYAoKTWFqb3JpdHkgb2YgZW1wbG95ZWVzIGhhdmUgdW5kZXJnb25lIHRyYWluaW5nIDItMyB0aW1lcyBpbiB0aGUgbGFzdCB5ZWFyLgoKIyBXb3JrTGlmZUJhbGFuY2UgRGlzdHJpYnV0aW9uCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBXb3JrTGlmZUJhbGFuY2UpKSArCiAgZ2VvbV9iYXIoKSArCiAgZ2VvbV90ZXh0KAogICAgc3RhdCA9ICJjb3VudCIsCiAgICBhZXMobGFiZWwgPSAuLmNvdW50Li4pLAogICAgdmp1c3QgPSAtMC42LCBzaXplID0gNCwgY29sb3IgPSAiYmxhY2siCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGV4cGFuZCA9IGV4cGFuc2lvbihtdWx0ID0gYygwLjAyLCAwLjE1KSkpICsgIAogIHRoZW1lX2Vjb25vbWlzdCgpICsKICBsYWJzKHRpdGxlID0gIldvcmsgTGlmZSBCYWxhbmNlIERpc3RyaWJ1dGlvbiIsIHggPSAiV29yayBMaWZlIEJhbGFuY2UgTGV2ZWwiLCB5ID0gIkNvdW50IikgKwogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKYGBgCgpNYWpvcml0eSBvZiBlbXBsb3llZXMgaGF2ZSBhIHdvcmsgbGlmZSBiYWxhbmNlIGxldmVsIG9mIDMsIHdpdGggbGV2ZWwgMSBiZWluZyB0aGUgbGVhc3QgY29tbW9uLgoKIyBZZWFyc0F0Q29tcGFueSBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IFllYXJzQXRDb21wYW55KSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpICsKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJZZWFycyBBdCBDb21wYW55IERpc3RyaWJ1dGlvbiIsIHggPSAiWWVhcnMgQXQgQ29tcGFueSIsIHkgPSAiQ291bnQiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKICApCmBgYAoKVGhlIFllYXJzIEF0IENvbXBhbnkgZmVhdHVyZSBhcHBlYXJzIHRvIGJlIHJpZ2h0IHNrZXdlZCB3aXRoIG1vc3QgZW1wbG95ZWVzIGhhdmluZyBiZXR3ZWVuIDAtMTAgeWVhcnMgYXQgdGhlIGNvbXBhbnkuCgojIFllYXJzSW5DdXJyZW50Um9sZSBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IFllYXJzSW5DdXJyZW50Um9sZSkpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKSArCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiWWVhcnMgSW4gQ3VycmVudCBSb2xlIERpc3RyaWJ1dGlvbiIsIHggPSAiWWVhcnMgSW4gQ3VycmVudCBSb2xlIiwgeSA9ICJDb3VudCIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAxMikpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMTIpKQogICAgKQogICkKYGBgCgpUaGUgWWVhcnMgSW4gQ3VycmVudCBSb2xlIGZlYXR1cmUgYXBwZWFycyB0byBiZSByaWdodCBza2V3ZWQgd2l0aCBtb3N0IGVtcGxveWVlcyBoYXZpbmcgYmV0d2VlbiAwLTcgeWVhcnMgaW4gdGhlaXIgY3VycmVudCByb2xlLgoKIyBZZWFyc1NpbmNlTGFzdFByb21vdGlvbiBEaXN0cmlidXRpb24KYGBge3J9CmdncGxvdChkYXRhLCBhZXMoeCA9IFllYXJzU2luY2VMYXN0UHJvbW90aW9uKSkgKyAKICBnZW9tX2hpc3RvZ3JhbShiaW53aWR0aCA9IDEpICsKICB0aGVtZV9lY29ub21pc3QoKSArCiAgbGFicyh0aXRsZSA9ICJZZWFycyBTaW5jZSBMYXN0IFByb21vdGlvbiBEaXN0cmlidXRpb24iLCB4ID0gIlllYXJzIFNpbmNlIExhc3QgUHJvbW90aW9uIiwgeSA9ICJDb3VudCIpICsgCiAgdGhlbWUoCiAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBtYXJnaW4gPSBtYXJnaW4oYiA9IDEyKSksCiAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSAxMikpLAogICAgYXhpcy50aXRsZS55ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbihyID0gMTIpKQogICAgKQogICkKYGBgCgpUaGUgWWVhcnMgU2luY2UgTGFzdCBQcm9tb3Rpb24gZmVhdHVyZSBhcHBlYXJzIHRvIGJlIHJpZ2h0IHNrZXdlZCB3aXRoIG1vc3QgZW1wbG95ZWVzIGhhdmluZyBiZXR3ZWVuIDAtMyB5ZWFycyBzaW5jZSB0aGVpciBsYXN0IHByb21vdGlvbi4KCiMgWWVhcnNXaXRoQ3Vyck1hbmFnZXIgRGlzdHJpYnV0aW9uCmBgYHtyfQpnZ3Bsb3QoZGF0YSwgYWVzKHggPSBZZWFyc1dpdGhDdXJyTWFuYWdlcikpICsgCiAgZ2VvbV9oaXN0b2dyYW0oYmlud2lkdGggPSAxKSArCiAgdGhlbWVfZWNvbm9taXN0KCkgKwogIGxhYnModGl0bGUgPSAiWWVhcnMgV2l0aCBDdXJyZW50IE1hbmFnZXIgRGlzdHJpYnV0aW9uIiwgeCA9ICJZZWFycyBXaXRoIEN1cnJlbnQgTWFuYWdlciIsIHkgPSAiQ291bnQiKSArIAogIHRoZW1lKAogICAgcGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSwgbWFyZ2luID0gbWFyZ2luKGIgPSAxMikpLAogICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KG1hcmdpbiA9IG1hcmdpbih0ID0gMTIpKSwKICAgIGF4aXMudGl0bGUueSA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4ociA9IDEyKSkKICAgICkKICApCmBgYAoKVGhlIFllYXJzIFdpdGggQ3VycmVudCBNYW5hZ2VyIGZlYXR1cmUgYXBwZWFycyB0byBiZSByaWdodCBza2V3ZWQgd2l0aCBtb3N0IGVtcGxveWVlcyBoYXZpbmcgYmV0d2VlbiAwLTcgeWVhcnMgd2l0aCB0aGVpciBjdXJyZW50IG1hbmFnZXIuCgojIC0tLS0tLS0tLS0tLSBCaXZhcmlhdGUgQW5hbHlzaXMgLS0tLS0tLS0tLS0tLQoK